package com.redmoon.oa.kernel;

import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.nio.charset.StandardCharsets;
import java.security.PublicKey;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import com.cloudweb.oa.service.IUserService;
import com.cloudweb.oa.utils.ConfigUtil;
import com.cloudweb.oa.utils.ConstUtil;
import com.cloudweb.oa.utils.SpringUtil;
import com.cloudwebsoft.framework.util.LogUtil;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;

import cn.js.fan.util.DateUtil;
import cn.js.fan.util.ErrMsgException;
import cn.js.fan.util.StrUtil;
import cn.js.fan.web.Global;

import com.redmoon.oa.person.UserDb;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;

/**
 * <p>
 * Title:
 * </p>
 * 
 * <p>
 * Description:
 * </p>
 * 
 * <p>
 * Copyright: Copyright (c) 2006
 * </p>
 * 
 * <p>
 * Company:
 * </p>
 * 
 * @author not attributable
 * @version 1.0
 */
public class License {
	static License license = null;
	Element root;

	private static Object initLock = new Object();

	public static final String VERSION_STANDARD = "Standard";

	public static final String VERSION_PROFESSIONAL = "Professional";

	/**
	 * 曾经作为标准版，改为企业版2023/2/14
	 */
	public static final String VERSION_PLATFORM = "Platform";

	/**
	 * 平台版
	 */
	public static final String VERSION_PLATFORM_SRC = "Platform_src";

	/**
	 * 集团版（同时也是开发版）
	 */
	public static final String VERSION_PLATFORM_GROUP= "Platform_group";

	/**
	 * 未注册时显示为试用版
	 */
	public static final String TYPE_TRIAL = "trial";

	/**
	 * 注册后的版本
	 */
	public static final String TYPE_COMMERICAL = "commercial";

	/**
	 * 付费版，去掉logo、水印等，暂未投入使用
	 */
	public static final String TYPE_BIZ = "biz";

	/**
	 * 源码级，4.0以后已弃用
	 */
	@Deprecated
	public static final String TYPE_SRC = "src";

	/**
	 * OEM级 jfy 20150702
	 */
	public static final String TYPE_OEM = "oem";

	public static final String VERSION_TYPE_PREMIUM = "2";

	/**
	 * 仅ActiveX版流程设计器
	 */
	public static final String FLOW_DESIGNER_A = "0";

	String licenseStr = "";

	public String getLicenseStr() {
		return licenseStr;
	}

	public void setLicenseStr(String licenseStr) {
		this.licenseStr = licenseStr;
	}

	boolean valid = false;

	/**
	 * 单位注册码
	 */
	private String key;

	/**
	 * 节点事件脚本
	 */
	public static final String MODULE_ACTION_EVENT_SCRIPT = "actionEventScript";

	/**
	 * 组合型，含政府及企业
	 */
	public static final String KIND_COMB = "COMB"; // Combination

	/**
	 * 企业版
	 */
	public static final String KIND_COM = "COM";
	/**
	 * 政府版
	 */
	public static final String KIND_GOV = "GOV";
	
	/**
	 * hr解决方案
	 */
	public static final String SOLUTION_HR = "hrSolution";
	/**
	 * crm解决方案
	 */
	public static final String SOLUTION_CRM = "crmSolution";

	/**
	 * 任务解决方案
	 */
	public static final String SOLUTION_TASK = "taskSolution";
	
	/**
	 * 预算解决方案
	 */
	public static final String SOLUTION_BUDGET = "budgetSolution";
	
	/**
	 * 绩效考核解决方案
	 */
	public static final String SOLUTION_PERFORMANCE = "performanceSolution";
	
	/**
	 * 积分制解决方案
	 */
	public static final String SOLUTION_SCORE = "scoreSolution";
	
	private String id;

	public boolean isPortUnlimit() {
		return portUnlimit;
	}

	public void setPortUnlimit(boolean portUnlimit) {
		this.portUnlimit = portUnlimit;
	}

	private boolean portUnlimit;

	public License() {
	}

	public boolean isPlatform() {
		if (isPlatformSrc()) {
			return true;
		} else if (isPlatformGroup()) {
			return true;
		} else if (isPlatformSuper()) {
			return true;
		}
		return versionType.equals(VERSION_PLATFORM);
	}

	public boolean isStandard() {
		return versionType.equals(VERSION_STANDARD);
	}

	public boolean isProfessional() {
		return versionType.equals(VERSION_PROFESSIONAL);
	}

	public boolean isPlatformSrc() {
		/*if (isTrial()) {
			return false;
		}*/
		if (isPlatformSuper()) {
			return true;
		} else if (isPlatformGroup()) {
			return true;
		}
		/*if (isSrc()) {
			return true;
		}*/
		return versionType.equals(VERSION_PLATFORM_SRC);
	}

	public boolean isPlatformSuper() {
		return true;
	}

	public boolean isCloud() {
		return category.equals(ConstUtil.CATEGORY_CLOUD);
	}

	public boolean isPlatformGroup() {
		return versionType.equals(VERSION_PLATFORM_GROUP);
	}

	public boolean isGov() {
		return kind.equals(KIND_GOV);
	}

	public boolean isCom() {
		return kind.equals(KIND_COM);
	}

	public boolean isComb() {
		return kind.equals(KIND_COMB);
	}

	public boolean isValid() {
		return valid;
	}

	public Date getExpiresDate() {
		return expiresDate;
	}

	public String getCompany() {
		return company;
	}

	public String getType() {
		return type;
	}

	public int getUserCount() {
		return userCount;
	}

	public Date getCreateDate() {
		return createDate;
	}

	public String getDomain() {
		return domain;
	}

	public String getVersion() {
		return version;
	}

	public String getVersionType() {
		return versionType;
	}

	public String getKey() {
		return key;
	}

	public String getOfficeControlKey() {
		return officeControlKey;
	}

	public static License getInstance() {
		if (license == null) {
			synchronized (initLock) {
				license = new License();
				license.init();
			}
		}
		return license;
	}

	public void init() {
		verify();
	}

	public void toXML(String licenseXMLString) {
		SAXBuilder sb = new SAXBuilder();
		try {
			StringReader sr = new StringReader(licenseXMLString);
			Document doc = sb.build(sr);
			sr.close();

			root = doc.getRootElement();

			setId(root.getChild("id").getText());

			userCount = StrUtil.toInt(root.getChild("userCount").getText(), 20);
			expiresDate = DateUtil.parse(
					root.getChild("expiresDate").getText(), "yyyy-MM-dd");
			createDate = DateUtil.parse(
					root.getChild("creationDate").getText(), "yyyy-MM-dd");
			company = root.getChild("company").getText();
			type = root.getChild("type").getText();
			domain = root.getChild("domain").getText();

			setName(root.getChild("name").getText());

			// 2.2版后增加该项
			version = root.getChild("version").getText();
			versionType = root.getChild("versionType").getText();
			// 4.0后增加该项
			if (root.getChild("key") != null) {
				key = root.getChild("key").getText();
			}

			if (root.getChild("enterpriseNum") != null) {
				setEnterpriseNum(root.getChild("enterpriseNum").getText());
			}

			if (root.getChild("isTrial") != null) {
				trial = root.getChildText("isTrial").equals("true");
			}

			if (root.getChild("portUnlimit") != null) {
				portUnlimit = "true".equals(root.getChildText("portUnlimit"));
			}
		} catch (JDOMException | IOException e) {
			LogUtil.getLog(getClass()).error(e);
		}
	}

	/**
	 * 根据公钥对license.dat进行验证并重建XML Document
	 * 
	 * @return boolean
	 */
	public boolean verify() {
		try {
			Resource resource = new ClassPathResource("publickey.dat");
			InputStream inputStream = resource.getInputStream();

			java.io.ObjectInputStream in = new java.io.ObjectInputStream(inputStream);
			PublicKey pubkey = (PublicKey) in.readObject();
			in.close();

			ConfigUtil configUtil = SpringUtil.getBean(ConfigUtil.class);
			inputStream = configUtil.getFile("license.dat");
			if (inputStream != null) {
				in = new java.io.ObjectInputStream(inputStream);
				// 取得license.xml
				String info = (String) in.readObject();
				// 取得签名
				byte[] signed = (byte[]) in.readObject();
				in.close();

				java.security.Signature signetcheck = java.security.Signature.getInstance("DSA");
				signetcheck.initVerify(pubkey);
				signetcheck.update(info.getBytes(StandardCharsets.UTF_8));
				if (signetcheck.verify(signed)) {
					toXML(info);
					valid = true;
				} else {
					valid = false;
					LogUtil.getLog(getClass()).error("Cloud Web license is invalid. 请联系官方获取技术支持！");
				}
			}
		} catch (java.lang.Exception e) {
			licenseStr = "（未找到许可证文件，您的配置可能不正确，请参考安装说明运行 "
					+ Global.getFullRootPath() + "/setup/index.jsp）";
			LogUtil.getLog(getClass()).error(e);
		}
		return valid;
	}

	public void validate(HttpServletRequest request) throws ErrMsgException {
		validate();

		String serverName = request.getServerName().toLowerCase();

		if ("localhost".equals(serverName) || "127.0.0.1".equals(serverName)) {
			return;
		}
		if (domain == null || "".equals(domain)) {
			throw new ErrMsgException("许可证域名:" + domain + " 非法!");
		}
		if ("*".equals(domain)) {
			return;
		}
		String[] ary = StrUtil.split(domain.toLowerCase(), ",");
		int len = ary.length;
		for (int i = 0; i < len; i++) {
			if (serverName.indexOf(ary[i]) != -1) {
				return;
			}
		}
		throw new ErrMsgException("许可证中的域名非法!" + licenseStr);
	}

	public void validate() throws ErrMsgException {
		if (!valid) {
			userCount = TEST_VERSTION_USER_COUNT;
			// throw new ErrMsgException("许可证非法!" + licenseStr);
		}

		// 检查时间
		if (DateUtil.compare(new java.util.Date(), expiresDate) == 1) {
			throw new ErrMsgException("系统已到期!" + licenseStr);
		}

		// 检查用户数
		IUserService userService = SpringUtil.getBean(IUserService.class);
		int uCount = userService.getValidUserCount();

		if (uCount > userCount) {
			if (!"".equals(licenseStr)) {
				throw new ErrMsgException("许可证限定用户数不能大于" + userCount + "，" + licenseStr);
			}
			else {
				throw new ErrMsgException("许可证限定用户数不能大于" + userCount);
			}
		}

		// 检查是否含有isCloudDisk
		/*if (cloudDisk == null) {
			throw new ErrMsgException("许可证中网盘参数设置非法!" + licenseStr);
		}*/
		
		// 不允许使用老版许可证
		double intVer = StrUtil.toDouble(version, 1.0);
		if (intVer < 3) {
			throw new ErrMsgException("非法使用许可证！");
		}
	}

	public void setExpiresDate(Date expiresDate) {
		this.expiresDate = expiresDate;
	}

	public void setCompany(String company) {
		this.company = company;
	}

	public void setType(String type) {
		this.type = type;
	}

	public void setUserCount(int userCount) {
		this.userCount = userCount;
	}

	public void setCreateDate(Date createDate) {
		this.createDate = createDate;
	}

	public void setDomain(String domain) {
		this.domain = domain;
	}

	public void setVersion(String version) {
		this.version = version;
	}

	public void setVersionType(String versionType) {
		this.versionType = versionType;
	}

	public void setKey(String key) {
		this.key = key;
	}

	public void setOfficeControlKey(String officeControlKey) {
		this.officeControlKey = officeControlKey;
	}

	/**
	 * 能否使用模块
	 * @param moduleCode 模块编码        
	 * @return
	 */
	public boolean canUseModule(String moduleCode) {
		return true;
	}
	
	/**
	 * 能否使用解决方案
	 * 目前仅用于岗位管理
	 * @param solutionCode  解决方案编码
	 * @return
	 */
	public boolean canUseSolution(String solutionCode) {
		return true;
	}

	public String getKind() {
		return kind;
	}

	public void setEnterpriseNum(String enterpriseNum) {
		this.enterpriseNum = enterpriseNum;
	}

	public String getEnterpriseNum() {
		return enterpriseNum;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getName() {
		return name;
	}

	public boolean isTrial() {
		return trial;
	}

	/**
	 * 判断是否为付费版，去掉水印、logo
	 * 
	 * @return
	 */
	public boolean isBiz() {
		return type.equals(TYPE_BIZ);
	}

	public boolean isOem() {
		return type.equals(TYPE_OEM);
	}
	
	public boolean isFree() {
		return type.equals(TYPE_COMMERICAL);		
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getId() {
		return id;
	}

	public boolean isSolutionVer() {
		return isSolutionVer;
	}

	public void setSolutionVer(boolean isSolutionVer) {
		this.isSolutionVer = isSolutionVer;
	}
	
    /**
     * 检查许可证中对于解决方案是否控制
     * 在flow.Render及visual.Render中使用
     * @param formCode
     * @return
     * @throws ErrMsgException
     */
    public boolean checkSolution(String formCode) throws ErrMsgException {
    	// 如果是铂金版，则含有所有的解决方案
    	if (isPlatformSuper()) {
			return true;
		}
    	
    	// 积分配置表
    	if ("pointsys".equals(formCode)) {
    		if (!canUseSolution(com.redmoon.oa.kernel.License.SOLUTION_SCORE)) {
    			throw new ErrMsgException(getLicenseStr());
    		}
    	}
    	else if ("score_reported".equals(formCode)) {
    		if (!canUseSolution(com.redmoon.oa.kernel.License.SOLUTION_SCORE)) {
    			throw new ErrMsgException(getLicenseStr());
    		}
    	}
    	return true;
    }	

	public static final int TEST_VERSTION_USER_COUNT = 15;

	private Date expiresDate;
	private String company = "无";
	private String type = TYPE_TRIAL;
	private int userCount = TEST_VERSTION_USER_COUNT;
	private Date createDate;
	private String domain = "*";
	private String version = "";
	private String officeControlKey = "";
	private String versionType = "";

	private String kind = "";

	private String enterpriseNum;

	private String name;
	
	private boolean isSolutionVer = false;

	private int actionCount = 10000;

	private boolean trial = false;

	private String flowDesigner = "";

	public String getFlowDesigner() {
		return flowDesigner;
	}

	public String getCategory() {
		return category;
	}

	public void setCategory(String category) {
		this.category = category;
	}

	private String category = ConstUtil.CATEGORY_CLOUD;
}
